import requests
import json

from django.http import StreamingHttpResponse
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.views import APIView
from rest_framework.exceptions import ValidationError
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from rest_framework_simplejwt.authentication import JWTAuthentication

from apps.utils.response_utils import api_response, ResponseCode

from conf.evn import NEXT_PUBLIC_API_URL, NEXT_PUBLIC_APP_KEY
from .config import DifyConfig
from ..utils.pageNumberPagination import CustomPageNumberPagination


class ChatMessages(APIView):
    """
    发送流式聊天消息，并返回实时数据
    """

    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]
    @swagger_auto_schema(
        operation_description="发送流式聊天消息，并返回实时数据",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                "query": openapi.Schema(
                    type=openapi.TYPE_STRING, description="用户的查询问题"
                ),
                "inputs": openapi.Schema(
                    type=openapi.TYPE_OBJECT, description="传入 App 定义的各变量值"
                ),
                "response_mode": openapi.Schema(
                    type=openapi.TYPE_STRING,
                    description="返回模式, 'streaming' 或 'blocking'",
                ),
                "user": openapi.Schema(
                    type=openapi.TYPE_STRING, description="用户标识"
                ),
                "conversation_id": openapi.Schema(
                    type=openapi.TYPE_STRING, description="会话 ID, 可选"
                ),
                "auto_generate_name": openapi.Schema(
                    type=openapi.TYPE_BOOLEAN,
                    description="是否自动生成标题，默认 true",
                    default=True,
                ),
                "files": openapi.Schema(
                    type=openapi.TYPE_ARRAY,
                    items=openapi.Schema(
                        type=openapi.TYPE_OBJECT,
                        properties={
                            "type": openapi.Schema(
                                type=openapi.TYPE_STRING,
                                description="文件类型，目前仅支持image",
                            ),
                            "transfer_method": openapi.Schema(
                                type=openapi.TYPE_STRING,
                                description="传递方式: remote_url或local_file",
                            ),
                            "url": openapi.Schema(
                                type=openapi.TYPE_STRING,
                                description="图片地址(remote_url方式)",
                            ),
                            "upload_file_id": openapi.Schema(
                                type=openapi.TYPE_STRING,
                                description="上传文件ID(local_file方式)",
                            ),
                        },
                    ),
                    description="上传的文件列表",
                ),
            },
            required=["user"],
        ),
        responses={
            200: openapi.Response(
                description="消息发送成功，返回流式数据",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={"data": openapi.Schema(type=openapi.TYPE_STRING)},
                ),
            ),
            201: openapi.Response(
                description="消息发送成功，返回阻塞数据",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        "message": openapi.Schema(type=openapi.TYPE_STRING),
                        "task_id": openapi.Schema(
                            type=openapi.TYPE_STRING, description="任务 ID"
                        ),
                        "message_id": openapi.Schema(
                            type=openapi.TYPE_STRING, description="消息 ID"
                        ),
                        "conversation_id": openapi.Schema(
                            type=openapi.TYPE_STRING, description="会话 ID"
                        ),
                        "mode": openapi.Schema(
                            type=openapi.TYPE_STRING, description="返回模式"
                        ),
                        "answer": openapi.Schema(
                            type=openapi.TYPE_STRING, description="生成的回答"
                        ),
                        "metadata": openapi.Schema(
                            type=openapi.TYPE_OBJECT,
                            properties={
                                "retriever_resources": openapi.Schema(
                                    type=openapi.TYPE_ARRAY,
                                    items=openapi.Schema(type=openapi.TYPE_OBJECT),
                                ),
                                "usage": openapi.Schema(
                                    type=openapi.TYPE_OBJECT,
                                    properties={
                                        "prompt_tokens": openapi.Schema(
                                            type=openapi.TYPE_INTEGER
                                        ),
                                        "completion_tokens": openapi.Schema(
                                            type=openapi.TYPE_INTEGER
                                        ),
                                        "total_tokens": openapi.Schema(
                                            type=openapi.TYPE_INTEGER
                                        ),
                                        "currency": openapi.Schema(
                                            type=openapi.TYPE_STRING
                                        ),
                                        "latency": openapi.Schema(
                                            type=openapi.TYPE_NUMBER
                                        ),
                                    },
                                ),
                            },
                        ),
                        "created_at": openapi.Schema(
                            type=openapi.TYPE_INTEGER, description="消息创建时间"
                        ),
                    },
                ),
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"],
    )
    def post(self, request, *args, **kwargs):
        # API URL（请根据实际地址调整）
        api_url = f"{NEXT_PUBLIC_API_URL}/chat-messages"

        # API Key
        api_key = NEXT_PUBLIC_APP_KEY

        # 请求头
        headers = {
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json',
        }

        # 处理文件上传
        files = []
        # 处理remote_url方式的文件
        remote_files = request.data.get("files", [])
        if remote_files:
            files.extend(remote_files)

        # 处理local_file方式的文件
        uploaded_files = request.FILES.getlist("files")
        for file in uploaded_files:
            # 检查文件类型是否为图片
            if not file.content_type.startswith("image/"):
                return api_response(ResponseCode.BAD_REQUEST, "只支持上传图片文件")

            files.append(
                {
                    "type": "image",
                    "transfer_method": "local_file",
                    "upload_file_id": file.name,
                }
            )

        conversation_id = request.data.get("conversation_id")
        msg_input = request.data.get("inputs", {})
        product_name = msg_input.get("product_name", "")
        # 如果是新会话（无 conversation_id）
        if not conversation_id:
            if not product_name or product_name == "":
                return api_response(ResponseCode.BAD_REQUEST, "新会话必须提供商品名称")
            else:
                generated_query = "生成一个脚本"
        else:
            generated_query = request.data.get("query", "")

        # 构建请求数据
        data = {
            "inputs": msg_input,
            "query": generated_query,
            "response_mode": request.data.get("response_mode", "streaming"),
            "conversation_id": conversation_id,
            "user": request.data.get("user", "unknown"),
            "auto_generate_name": request.data.get("auto_generate_name", True),
            "files": files,
        }

        # 发起请求
        try:
            response = requests.post(api_url, headers=headers, data=json.dumps(data), stream=True)

            if response.status_code == 200:
                if data["response_mode"] == "streaming":
                    def generate():
                        for line in response.iter_lines(decode_unicode=True):
                            if line:
                                yield line

                    return StreamingHttpResponse(generate(), content_type='text/event-stream')

                else:  # 阻塞模式
                    # 解析阻塞模式的返回数据
                    response_json = response.json()
                    return api_response(ResponseCode.SUCCESS, "消息返回成功", response_json)

            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{response.text}")

        except requests.RequestException as e:
            raise ValidationError(f"请求失败：{str(e)}")


class ConversationListView(APIView):
    """
    获取当前用户的会话列表
    """
    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]

    @swagger_auto_schema(
        operation_description="获取当前用户的会话列表，返回置顶和非置顶会话合并后的结果，每个会话对象包含 is_pinned 字段",
        manual_parameters=[
            openapi.Parameter('user', openapi.IN_QUERY, description="用户标识", type=openapi.TYPE_STRING),
            openapi.Parameter('last_id', openapi.IN_QUERY, description="当前页最后一条记录的 ID，默认 null", type=openapi.TYPE_STRING),
            openapi.Parameter('limit', openapi.IN_QUERY,
                              description="一次请求返回多少条记录，默认 20 条，最大 100 条，最小 1 条。",
                              type=openapi.TYPE_INTEGER),
            openapi.Parameter('sort_by', openapi.IN_QUERY,
                              description="排序字段，默认 -updated_at（按更新时间倒序排列）；可选值：created_at, -created_at, updated_at, -updated_at",
                              type=openapi.TYPE_STRING),
        ],
        responses={
            200: openapi.Response(
                description="成功获取会话列表",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'limit': openapi.Schema(type=openapi.TYPE_INTEGER, description="返回条数"),
                        'has_more': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="是否还有更多会话"),
                        'data': openapi.Schema(
                            type=openapi.TYPE_ARRAY,
                            items=openapi.Schema(
                                type=openapi.TYPE_OBJECT,
                                properties={
                                    'id': openapi.Schema(type=openapi.TYPE_STRING, description="会话 ID"),
                                    'name': openapi.Schema(type=openapi.TYPE_STRING, description="会话名称"),
                                    'inputs': openapi.Schema(type=openapi.TYPE_OBJECT, description="用户输入参数"),
                                    'status': openapi.Schema(type=openapi.TYPE_STRING, description="会话状态"),
                                    'introduction': openapi.Schema(type=openapi.TYPE_STRING, description="会话介绍"),
                                    'created_at': openapi.Schema(type=openapi.TYPE_INTEGER, description="创建时间戳"),
                                    'updated_at': openapi.Schema(type=openapi.TYPE_INTEGER, description="更新时间戳"),
                                    'is_pinned': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="是否置顶"),
                                }
                            )
                        )
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def get(self, request, *args, **kwargs):
        # 获取查询参数
        user = request.query_params.get('user')
        last_id = request.query_params.get('last_id', None)
        try:
            limit = int(request.query_params.get('limit', 20))
        except ValueError:
            raise ValidationError("limit 参数必须为数字。")
        sort_by = request.query_params.get('sort_by', '-updated_at')

        # 验证 limit 参数
        if limit < 1 or limit > 100:
            raise ValidationError("limit 参数必须在 1 到 100 之间。")

        api_url = f"{NEXT_PUBLIC_API_URL}/conversations"

        # 构建请求头
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',
            'Content-Type': 'application/json',
        }

        # 公共请求参数（不包含 pinned）
        params_common = {
            'user': user,
            'last_id': last_id,
            'limit': limit,
            'sort_by': sort_by,
        }

        try:
            # 请求置顶会话列表（pinned=true）
            params_true = params_common.copy()
            params_true['pinned'] = "true"
            response_true = requests.get(api_url, headers=headers, params=params_true)

            # 请求非置顶会话列表（pinned=false）
            params_false = params_common.copy()
            params_false['pinned'] = "false"
            response_false = requests.get(api_url, headers=headers, params=params_false)

            if response_true.status_code == 200 and response_false.status_code == 200:
                data_true = response_true.json()
                data_false = response_false.json()
                # 在每个会话对象中添加 is_pinned 字段
                for item in data_true.get('data', []):
                    item['is_pinned'] = True
                for item in data_false.get('data', []):
                    item['is_pinned'] = False

                # 合并两组数据，并按 updated_at 降序排序
                combined_data = data_true.get('data', []) + data_false.get('data', [])
                combined_data.sort(key=lambda x: x.get('updated_at', 0), reverse=True)

                # 如果任一组还有更多，则总结果标记为 has_more 为 True
                has_more = data_true.get('has_more', False) or data_false.get('has_more', False)

                result = {
                    'limit': limit,
                    'has_more': has_more,
                    'data': combined_data,
                }
                return api_response(ResponseCode.SUCCESS, '获取成功', result)
            else:
                error_msg = f"请求失败: pinned -> {response_true.text}, unpinned -> {response_false.text}"
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, error_msg)

        except requests.RequestException as e:
            raise ValidationError(f"请求失败：{str(e)}")


class MessageHistoryView(APIView):
    """
    获取会话历史消息
    """

    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]
    @swagger_auto_schema(
        operation_description="获取会话历史消息",
        manual_parameters=[
            openapi.Parameter('conversation_id', openapi.IN_QUERY, description="会话 ID", type=openapi.TYPE_STRING),
            openapi.Parameter('user', openapi.IN_QUERY, description="用户标识", type=openapi.TYPE_STRING),
            openapi.Parameter('first_id', openapi.IN_QUERY, description="当前页第一条聊天记录的 ID，默认 null",
                              type=openapi.TYPE_STRING),
            openapi.Parameter('limit', openapi.IN_QUERY, description="一次请求返回多少条聊天记录，默认 20 条",
                              type=openapi.TYPE_INTEGER),
        ],
        responses={
            200: openapi.Response(
                description="成功获取历史消息",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'data': openapi.Schema(
                            type=openapi.TYPE_ARRAY,
                            items=openapi.Schema(
                                type=openapi.TYPE_OBJECT,
                                properties={
                                    'id': openapi.Schema(type=openapi.TYPE_STRING, description="消息 ID"),
                                    'conversation_id': openapi.Schema(type=openapi.TYPE_STRING, description="会话 ID"),
                                    'inputs': openapi.Schema(type=openapi.TYPE_OBJECT, description="用户输入参数"),
                                    'query': openapi.Schema(type=openapi.TYPE_STRING,
                                                            description="用户输入 / 提问内容"),
                                    'message_files': openapi.Schema(
                                        type=openapi.TYPE_ARRAY,
                                        items=openapi.Schema(
                                            type=openapi.TYPE_OBJECT,
                                            properties={
                                                'id': openapi.Schema(type=openapi.TYPE_STRING, description="文件 ID"),
                                                'type': openapi.Schema(type=openapi.TYPE_STRING,
                                                                       description="文件类型"),
                                                'url': openapi.Schema(type=openapi.TYPE_STRING,
                                                                      description="文件预览地址"),
                                                'belongs_to': openapi.Schema(type=openapi.TYPE_STRING,
                                                                             description="文件归属方")
                                            }
                                        )
                                    ),
                                    'answer': openapi.Schema(type=openapi.TYPE_STRING, description="回答消息内容"),
                                    'created_at': openapi.Schema(type=openapi.TYPE_INTEGER, description="创建时间戳"),
                                    'feedback': openapi.Schema(
                                        type=openapi.TYPE_OBJECT,
                                        properties={
                                            'rating': openapi.Schema(type=openapi.TYPE_STRING,
                                                                     description="点点赞/点踩"),
                                        }
                                    ),
                                    'retriever_resources': openapi.Schema(
                                        type=openapi.TYPE_ARRAY,
                                        items=openapi.Schema(
                                            type=openapi.TYPE_OBJECT,
                                            properties={
                                                'dataset_id': openapi.Schema(type=openapi.TYPE_STRING,
                                                                             description="数据集 ID"),
                                                'dataset_name': openapi.Schema(type=openapi.TYPE_STRING,
                                                                               description="数据集名称"),
                                                'document_id': openapi.Schema(type=openapi.TYPE_STRING,
                                                                              description="文档 ID"),
                                                'document_name': openapi.Schema(type=openapi.TYPE_STRING,
                                                                                description="文档名称"),
                                                'content': openapi.Schema(type=openapi.TYPE_STRING,
                                                                          description="文档内容"),
                                            }
                                        )
                                    ),
                                }
                            )
                        ),
                        'has_more': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="是否还有更多消息"),
                        'limit': openapi.Schema(type=openapi.TYPE_INTEGER, description="返回条数"),
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def get(self, request, *args, **kwargs):
        # 获取查询参数
        conversation_id = request.query_params.get('conversation_id')
        user = request.query_params.get('user')
        first_id = request.query_params.get('first_id', None)
        limit = int(request.query_params.get('limit', 20))

        # 验证 limit 参数
        if limit < 1 or limit > 100:
            raise ValidationError("limit 参数必须在 1 到 100 之间。")

        api_url = f"{NEXT_PUBLIC_API_URL}/messages"

        # 构建请求头
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',  # 替换为实际的 API 密钥
            'Content-Type': 'application/json',
        }

        # 构建请求体
        data = {
            'conversation_id': conversation_id,
            'user': user,
            'first_id': first_id,
            'limit': limit,
        }

        # 发起请求
        try:
            response = requests.get(api_url, headers=headers, params=data)

            if response.status_code == 200:
                return api_response(ResponseCode.SUCCESS, '获取历史消息成功', response.json())
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败:{response.text}')

        except requests.RequestException as e:
            raise ValidationError(f"请求失败：{str(e)}")


class RenameConversationView(APIView):
    """
    会话重命名接口
    """

    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]
    @swagger_auto_schema(
        operation_description="重命名会话",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'name': openapi.Schema(type=openapi.TYPE_STRING, description="会话名称"),
                'auto_generate': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="是否自动生成会话名称"),
                'user': openapi.Schema(type=openapi.TYPE_STRING, description="用户标识"),
            }
        ),
        responses={
            200: openapi.Response(
                description="成功重命名会话",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'id': openapi.Schema(type=openapi.TYPE_STRING, description="会话 ID"),
                        'name': openapi.Schema(type=openapi.TYPE_STRING, description="会话名称"),
                        'inputs': openapi.Schema(type=openapi.TYPE_OBJECT, description="用户输入参数"),
                        'status': openapi.Schema(type=openapi.TYPE_STRING, description="会话状态"),
                        'introduction': openapi.Schema(type=openapi.TYPE_STRING, description="会话介绍"),
                        'created_at': openapi.Schema(type=openapi.TYPE_INTEGER, description="创建时间戳"),
                        'updated_at': openapi.Schema(type=openapi.TYPE_INTEGER, description="更新时间戳"),
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def post(self, request, conversation_id, *args, **kwargs):
        # 获取请求数据
        name = request.data.get('name', None)
        auto_generate = request.data.get('auto_generate', False)
        user = request.data.get('user', None)

        # 如果 auto_generate 为 True，则 name 不能输入，且会话标题由聊天内容自动生成
        if auto_generate:
            if name is not None and name != '':
                return api_response(ResponseCode.BAD_REQUEST, "当 auto_generate 为 True 时，name 不能提供。")
            # 根据聊天内容生成标题，这里需要具体实现自动生成标题的逻辑
            name = None  # 不传递 name，接口根据聊天内容生成标题

        # 构建请求数据
        data = {
            'name': name,  # 如果 auto_generate 为 False，则使用用户提供的 name
            'auto_generate': auto_generate,
            'user': user,
        }

        # 发送请求到外部 API
        api_url = f"{NEXT_PUBLIC_API_URL}/conversations/{conversation_id}/name"
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',  # 替换为实际的 API 密钥
            'Content-Type': 'application/json',
        }

        try:
            response = requests.post(api_url, headers=headers, json=data)

            if response.status_code == 200:
                # 返回成功响应
                return api_response(ResponseCode.SUCCESS, '会话重命名成功', response.json())
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败:{response.text}')

        except requests.RequestException as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{str(e)}")


class DeleteConversationView(APIView):
    """
    删除会话接口
    """

    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]
    @swagger_auto_schema(
        operation_description="删除会话",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'user': openapi.Schema(type=openapi.TYPE_STRING, description="用户标识"),
            }
        ),
        responses={
            200: openapi.Response(
                description="成功删除会话",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'result': openapi.Schema(type=openapi.TYPE_STRING, description="固定返回 success")
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def delete(self, request, conversation_id, *args, **kwargs):
        # 获取用户标识
        user = request.data.get('user', None)

        if not user:
            return api_response(ResponseCode.BAD_REQUEST, "用户标识不能为空。")

        # 构建请求数据
        data = {
            'user': user,
        }

        # 发送请求到外部 API
        api_url = f"{NEXT_PUBLIC_API_URL}/conversations/{conversation_id}"
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',  # 替换为实际的 API 密钥
            'Content-Type': 'application/json',
        }

        try:
            response = requests.delete(api_url, headers=headers, json=data)

            if response.status_code == 200:
                # 返回成功响应
                return api_response(ResponseCode.SUCCESS, '会话删除成功', {'result': 'success'})
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败:{response.text}')

        except requests.RequestException as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{str(e)}")


class MessageFeedbackView(APIView):
    """
    消息反馈接口（点赞/点踩/撤销点赞）
    """

    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]
    @swagger_auto_schema(
        operation_description="用户对消息进行反馈（点赞、点踩、撤销点赞）",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'rating': openapi.Schema(type=openapi.TYPE_STRING,
                                         description="点赞 like, 点踩 dislike, 撤销点赞 null"),
                'user': openapi.Schema(type=openapi.TYPE_STRING, description="用户标识"),
                'content': openapi.Schema(type=openapi.TYPE_STRING, description="反馈的具体信息"),
            }
        ),
        responses={
            200: openapi.Response(
                description="成功处理消息反馈",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'result': openapi.Schema(type=openapi.TYPE_STRING, description="固定返回 success")
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def post(self, request, message_id, *args, **kwargs):
        # 获取请求数据
        rating = request.data.get('rating', None)
        user = request.data.get('user', None)
        content = request.data.get('content', None)

        # 验证输入参数
        if not rating or not user:
            return api_response(ResponseCode.BAD_REQUEST, "rating 和 user 不能为空。")
        if rating not in ['like', 'dislike', 'null']:
            return api_response(ResponseCode.BAD_REQUEST, "rating 参数无效，应为 like, dislike 或 null。")

        # 构建请求数据
        data = {
            'rating': rating,
            'user': user,
            'content': content,
        }

        # 发送请求到外部 API
        api_url = f"{NEXT_PUBLIC_API_URL}/messages/{message_id}/feedbacks"
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',  # 替换为实际的 API 密钥
            'Content-Type': 'application/json',
        }

        try:
            response = requests.post(api_url, headers=headers, json=data)

            if response.status_code == 200:
                # 返回成功响应
                return api_response(ResponseCode.SUCCESS, '消息反馈成功', {'result': 'success'})
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败:{response.text}')

        except requests.RequestException as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{str(e)}")


class StopResponseView(APIView):
    """
    停止响应接口
    仅支持流式模式。
    """

    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]
    @swagger_auto_schema(
        operation_description="停止响应接口，仅支持流式模式",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'user': openapi.Schema(type=openapi.TYPE_STRING, description="用户标识"),
            }
        ),
        responses={
            200: openapi.Response(
                description="成功停止响应",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'result': openapi.Schema(type=openapi.TYPE_STRING, description="固定返回 success")
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def post(self, request, task_id, *args, **kwargs):
        # 获取请求数据
        user = request.data.get('user', None)

        if not user:
            return api_response(ResponseCode.BAD_REQUEST, "用户标识不能为空。")

        # 构建请求数据
        data = {
            'user': user,
        }

        # 发送请求到外部 API
        api_url = f"{NEXT_PUBLIC_API_URL}/chat-messages/{task_id}/stop"
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',  # 替换为实际的 API 密钥
            'Content-Type': 'application/json',
        }

        try:
            response = requests.post(api_url, headers=headers, json=data)

            if response.status_code == 200:
                # 返回成功响应
                return api_response(ResponseCode.SUCCESS, '停止响应成功', {'result': 'success'})
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败:{response.text}')

        except requests.RequestException as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{str(e)}")


class AppInfoView(APIView):
    """
    获取应用基本信息接口
    """

    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]
    @swagger_auto_schema(
        operation_description="获取应用的基本信息",
        responses={
            200: openapi.Response(
                description="成功获取应用基本信息",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'name': openapi.Schema(type=openapi.TYPE_STRING, description="应用名称"),
                        'description': openapi.Schema(type=openapi.TYPE_STRING, description="应用描述"),
                        'tags': openapi.Schema(
                            type=openapi.TYPE_ARRAY,
                            items=openapi.Schema(type=openapi.TYPE_STRING),
                            description="应用标签，包含一个或多个标签"
                        )
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def get(self, request, *args, **kwargs):
        # 构建请求数据
        api_url = f"{NEXT_PUBLIC_API_URL}/info"
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',
            'Content-Type': 'application/json',
        }

        try:
            response = requests.get(api_url, headers=headers)

            if response.status_code == 200:
                return api_response(ResponseCode.SUCCESS, '获取应用信息成功', response.json())
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败:{response.text}')

        except requests.RequestException as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{str(e)}")


class AppParametersView(APIView):
    """
    获取应用参数接口
    """

    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]
    @swagger_auto_schema(
        operation_description="获取应用的参数配置",
        responses={
            200: openapi.Response(
                description="成功获取应用参数",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'introduction': openapi.Schema(type=openapi.TYPE_STRING, description="应用的开场白"),
                        'user_input_form': openapi.Schema(
                            type=openapi.TYPE_ARRAY,
                            items=openapi.Schema(
                                type=openapi.TYPE_OBJECT,
                                properties={
                                    'text-input': openapi.Schema(
                                        type=openapi.TYPE_OBJECT,
                                        properties={
                                            'label': openapi.Schema(type=openapi.TYPE_STRING,
                                                                    description="文本输入控件的展示标签名"),
                                            'variable': openapi.Schema(type=openapi.TYPE_STRING, description="控件 ID"),
                                            'required': openapi.Schema(type=openapi.TYPE_BOOLEAN,
                                                                       description="是否为必填项"),
                                            'max_length': openapi.Schema(type=openapi.TYPE_INTEGER,
                                                                         description="最大字符长度"),
                                            'default': openapi.Schema(type=openapi.TYPE_STRING, description="默认值")
                                        }
                                    ),
                                    'paragraph': openapi.Schema(
                                        type=openapi.TYPE_OBJECT,
                                        properties={
                                            'label': openapi.Schema(type=openapi.TYPE_STRING,
                                                                    description="段落文本输入控件的展示标签名"),
                                            'variable': openapi.Schema(type=openapi.TYPE_STRING, description="控件 ID"),
                                            'required': openapi.Schema(type=openapi.TYPE_BOOLEAN,
                                                                       description="是否为必填项"),
                                            'default': openapi.Schema(type=openapi.TYPE_STRING, description="默认值")
                                        }
                                    ),
                                    'select': openapi.Schema(
                                        type=openapi.TYPE_OBJECT,
                                        properties={
                                            'label': openapi.Schema(type=openapi.TYPE_STRING,
                                                                    description="下拉控件的展示标签名"),
                                            'variable': openapi.Schema(type=openapi.TYPE_STRING, description="控件 ID"),
                                            'required': openapi.Schema(type=openapi.TYPE_BOOLEAN,
                                                                       description="是否为必填项"),
                                            'default': openapi.Schema(type=openapi.TYPE_STRING, description="默认值"),
                                            'options': openapi.Schema(
                                                type=openapi.TYPE_ARRAY,
                                                items=openapi.Schema(type=openapi.TYPE_STRING),
                                                description="下拉控件的选项值"
                                            )
                                        }
                                    )
                                }
                            ),
                            description="用户输入表单配置"
                        ),
                        'file_upload': openapi.Schema(
                            type=openapi.TYPE_OBJECT,
                            properties={
                                'image': openapi.Schema(
                                    type=openapi.TYPE_OBJECT,
                                    properties={
                                        'enabled': openapi.Schema(type=openapi.TYPE_BOOLEAN,
                                                                  description="图片上传是否开启"),
                                        'number_limits': openapi.Schema(type=openapi.TYPE_INTEGER,
                                                                        description="图片数量限制"),
                                        'transfer_methods': openapi.Schema(
                                            type=openapi.TYPE_ARRAY,
                                            items=openapi.Schema(type=openapi.TYPE_STRING),
                                            description="传递方式列表，包含 remote_url 和 local_file"
                                        )
                                    }
                                )
                            }
                        ),
                        'system_parameters': openapi.Schema(
                            type=openapi.TYPE_OBJECT,
                            properties={
                                'file_size_limit': openapi.Schema(type=openapi.TYPE_INTEGER,
                                                                  description="文档上传大小限制 (MB)"),
                                'image_file_size_limit': openapi.Schema(type=openapi.TYPE_INTEGER,
                                                                        description="图片文件上传大小限制（MB）"),
                                'audio_file_size_limit': openapi.Schema(type=openapi.TYPE_INTEGER,
                                                                        description="音频文件上传大小限制 (MB)"),
                                'video_file_size_limit': openapi.Schema(type=openapi.TYPE_INTEGER,
                                                                        description="视频文件上传大小限制 (MB)")
                            }
                        )
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def get(self, request, *args, **kwargs):
        # 构建请求数据
        api_url = f"{NEXT_PUBLIC_API_URL}/parameters"
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',
            'Content-Type': 'application/json',
        }

        try:
            response = requests.get(api_url, headers=headers)

            if response.status_code == 200:
                return api_response(ResponseCode.SUCCESS, '获取应用参数成功', response.json())
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败:{response.text}')

        except requests.RequestException as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{str(e)}")


class AppMetaView(APIView):
    """
    获取应用Meta信息接口
    """

    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]
    @swagger_auto_schema(
        operation_description="获取应用的Meta信息，包括工具图标等",
        responses={
            200: openapi.Response(
                description="成功获取应用Meta信息",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'tool_icons': openapi.Schema(
                            type=openapi.TYPE_OBJECT,
                            additional_properties=openapi.Schema(
                                type=openapi.TYPE_OBJECT,
                                properties={
                                    'background': openapi.Schema(type=openapi.TYPE_STRING,
                                                                 description="图标的背景色 (Hex格式)"),
                                    'content': openapi.Schema(type=openapi.TYPE_STRING, description="图标的表情内容"),
                                    'icon': openapi.Schema(
                                        type=openapi.TYPE_STRING,
                                        description="图标URL，指向工具图标的资源"
                                    )
                                }
                            ),
                            description="工具图标信息"
                        )
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def get(self, request, *args, **kwargs):
        # 构建请求数据
        api_url = f"{NEXT_PUBLIC_API_URL}/meta"
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',
            'Content-Type': 'application/json',
        }

        try:
            response = requests.get(api_url, headers=headers)

            if response.status_code == 200:
                return api_response(ResponseCode.SUCCESS, '获取应用Meta信息成功', response.json())
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败:{response.text}')

        except requests.RequestException as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{str(e)}")


class PinConversationView(APIView):
    """
    置顶对话接口
    """
    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]

    @swagger_auto_schema(
        operation_description="置顶指定对话，将对话的置顶状态设置为 True",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'user': openapi.Schema(type=openapi.TYPE_STRING, description="用户标识"),
            }
        ),
        responses={
            200: openapi.Response(
                description="成功置顶对话",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'result': openapi.Schema(
                            type=openapi.TYPE_STRING, description="返回信息"
                        ),
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def patch(self, request, conversation_id, *args, **kwargs):
        user = request.data.get('user', None)
        # 构建请求数据
        api_url = f"{NEXT_PUBLIC_API_URL}/conversations/{conversation_id}/pin"
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',
            'Content-Type': 'application/json',
        }

        data = {
            'user': user,
        }

        try:
            response = requests.patch(api_url, headers=headers, json=data)
            if response.status_code == 200:
                return api_response(ResponseCode.SUCCESS, '置顶成功', response.json())
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败: {response.text}')
        except requests.RequestException as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{str(e)}")


class UnpinConversationView(APIView):
    """
    取消置顶对话接口
    """
    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]

    @swagger_auto_schema(
        operation_description="取消置顶指定对话，将对话的置顶状态设置为 False",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'user': openapi.Schema(type=openapi.TYPE_STRING, description="用户标识"),
            }
        ),
        responses={
            200: openapi.Response(
                description="成功取消置顶对话",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'conversation_id': openapi.Schema(
                            type=openapi.TYPE_STRING, description="对话 ID"
                        ),
                        'is_pinned': openapi.Schema(
                            type=openapi.TYPE_BOOLEAN, description="置顶状态"
                        ),
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["对话模块"]
    )
    def patch(self, request, conversation_id, *args, **kwargs):
        user = request.data.get('user', None)
        # 构建请求数据
        api_url = f"{NEXT_PUBLIC_API_URL}/conversations/{conversation_id}/unpin"
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',
            'Content-Type': 'application/json',
        }

        data = {
            'user': user,
        }

        try:
            response = requests.patch(api_url, headers=headers, json=data)
            if response.status_code == 200:
                return api_response(ResponseCode.SUCCESS, '取消置顶成功', response.json())
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败: {response.text}')
        except requests.RequestException as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{str(e)}")


class StatisticTokenCostsView(APIView):
    """
    统计用户token调用接口
    """
    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]

    @swagger_auto_schema(
        operation_description="统计指定用户在给定时间范围内的token调用情况（时间范围非必传）",
        manual_parameters=[
            openapi.Parameter(
                'user',
                in_=openapi.IN_QUERY,
                type=openapi.TYPE_STRING,
                description="用户标识",
                required=True,
            ),
            openapi.Parameter(
                'start',
                in_=openapi.IN_QUERY,
                type=openapi.TYPE_STRING,
                description="开始时间，格式：YYYY-MM-DD HH:mm（非必传）",
                required=False,
            ),
            openapi.Parameter(
                'end',
                in_=openapi.IN_QUERY,
                type=openapi.TYPE_STRING,
                description="结束时间，格式：YYYY-MM-DD HH:mm（非必传）",
                required=False,
            ),
        ],
        responses={
            200: openapi.Response(
                description="成功统计token调用",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'data': openapi.Schema(
                            type=openapi.TYPE_ARRAY,
                            items=openapi.Schema(
                                type=openapi.TYPE_OBJECT,
                                properties={
                                    'currency': openapi.Schema(type=openapi.TYPE_STRING, description="货币类型"),
                                    'date': openapi.Schema(type=openapi.TYPE_STRING, description="日期"),
                                    'token_count': openapi.Schema(type=openapi.TYPE_INTEGER, description="token数量"),
                                    'total_price': openapi.Schema(type=openapi.TYPE_STRING, description="总价格"),
                                }
                            ),
                            description="统计数据列表"
                        )
                    }
                )
            ),
            400: openapi.Response(description="请求无效"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["统计模块"]
    )
    def get(self, request, *args, **kwargs):
        user = request.query_params.get('user')
        # 从查询参数中获取可选的时间范围
        start = request.query_params.get('start')
        end = request.query_params.get('end')
        page = request.query_params.get("pageNo", 1)
        page_size = request.query_params.get("pageSize", 10)

        # 构建请求的API URL及查询参数
        api_url = f"{NEXT_PUBLIC_API_URL}/statistic/token-costs"
        headers = {
            'Authorization': f'Bearer {NEXT_PUBLIC_APP_KEY}',
            'Content-Type': 'application/json',
        }
        params = {}
        if start:
            params['start'] = start
        if end:
            params['end'] = end

        data = {'user': user}

        try:
            response = requests.get(api_url, headers=headers, params=params, json=data)
            if response.status_code == 200:
                response_data = response.json()
                # 获取上游返回的全部数据列表（假定数据在 data 字段内）
                data_list = response_data.get('data', [])

                # 分页处理：使用自定义分页器对 data_list 进行分页
                paginator = CustomPageNumberPagination()
                # 设置分页参数
                paginator.page_size = int(page_size)
                paginator.page_query_param = 'pageNo'
                paginator.page_size_query_param = 'pageSize'
                paginated_data = paginator.paginate_queryset(data_list, request, view=self)
                paginated_response = paginator.get_paginated_response(paginated_data)

                return api_response(ResponseCode.SUCCESS, '统计成功', paginated_response.data)
            else:
                return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f'请求失败: {response.text}')
        except requests.RequestException as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"请求失败：{str(e)}")


class UpdateDifyConfigView(APIView):
    """
    修改Dify智能体配置接口
    """

    permission_classes = [AllowAny]
    authentication_classes = [JWTAuthentication]

    def _login_dify(self):
        """登录Dify获取token"""
        login_url = "http://localhost/console/api/login"
        login_data = {
            "email": "3186086557@qq.com",
            "password": "3186086557jj",
            "language": "zh-Hans",
            "remember_me": True,
        }
        try:
            response = requests.post(login_url, json=login_data)
            if response.status_code == 200:
                data = response.json()
                DifyConfig.update_tokens(
                    data["data"]["access_token"], data["data"]["refresh_token"]
                )
                return True
            return False
        except Exception:
            return False

    def _get_dify_config(self):
        """获取Dify配置"""
        headers = {"Authorization": f"Bearer {DifyConfig.get_access_token()}"}
        url = "http://localhost/console/api/apps/7b3540f4-fd8a-4de9-ad0e-72f6e85e76f4"

        try:
            response = requests.get(url, headers=headers)
            if response.status_code == 401:  # token过期
                if self._login_dify():  # 重新登录
                    return self._get_dify_config()  # 重试请求
                return None
            elif response.status_code == 200:
                return response.json()
            return None
        except Exception:
            return None

    def _update_dify_config(self, config_data):
        """更新Dify配置"""
        headers = {"Authorization": f"Bearer {DifyConfig.get_access_token()}"}
        url = "http://localhost/console/api/apps/7b3540f4-fd8a-4de9-ad0e-72f6e85e76f4/model-config"

        try:
            response = requests.post(url, headers=headers, json=config_data)
            if response.status_code == 401:  # token过期
                if self._login_dify():  # 重新登录
                    return self._update_dify_config(config_data)  # 重试请求
                return False
            return response.status_code == 200
        except Exception:
            return False

    @swagger_auto_schema(
        operation_description="修改Dify智能体的提示词和变量配置",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                "pre_prompt": openapi.Schema(
                    type=openapi.TYPE_STRING, description="提示词"
                ),
                "user_input_form": openapi.Schema(
                    type=openapi.TYPE_ARRAY,
                    items=openapi.Schema(
                        type=openapi.TYPE_OBJECT,
                        properties={
                            #TODO: 补全变量类型
                            "text-input": openapi.Schema(
                                type=openapi.TYPE_OBJECT,
                                properties={
                                    "label": openapi.Schema(type=openapi.TYPE_STRING, description="变量 Key"),
                                    "variable": openapi.Schema(
                                        type=openapi.TYPE_STRING,
                                        description="变量名称",
                                    ),
                                    "required": openapi.Schema(
                                        type=openapi.TYPE_BOOLEAN,
                                        description="是否为必填项",
                                    ),
                                    "max_length": openapi.Schema(
                                        type=openapi.TYPE_INTEGER,
                                        description="最大字符长度",
                                    ),
                                    "default": openapi.Schema(type=openapi.TYPE_STRING),
                                },
                            )
                        },
                    ),
                    description="用户输入表单配置",
                ),
            },
        ),
        responses={
            200: openapi.Response(description="配置更新成功"),
            400: openapi.Response(description="请求参数错误"),
            500: openapi.Response(description="服务器错误"),
        },
        tags=["智能体配置"],
    )
    def post(self, request, *args, **kwargs):
        # 获取请求数据
        pre_prompt = request.data.get("pre_prompt", None)
        user_input_form = request.data.get("user_input_form", None)


        # 获取当前配置
        current_config = self._get_dify_config()
        if not current_config:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, "获取当前配置失败")

        # 更新配置
        model_config = current_config["model_config"]
        model_config["pre_prompt"] = pre_prompt
        model_config["user_input_form"] = user_input_form

        # 构建更新数据
        update_data = model_config

        # 发送更新请求
        if self._update_dify_config(update_data):
            return api_response(ResponseCode.SUCCESS, "配置更新成功")
        return api_response(ResponseCode.INTERNAL_SERVER_ERROR, "配置更新失败")
